package com.outsourcing.bottle.ui;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Pattern;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.hardware.Camera.Size;
import android.media.ExifInterface;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.Display;
import android.view.KeyEvent;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;

import com.outsourcing.bottle.R;
import com.outsourcing.bottle.util.AppContext;
/**
 * 
 * @author 06peng
 *
 */
public class CameraActivity extends Activity implements OnClickListener, Callback {
	private SurfaceView mSurfaceView;
	private SurfaceHolder mSurfaceHolder;
	private Camera mCamera = null;
	private boolean mPreviewRunning;
	private int IMG_Width = 640;
	private int IMG_Height = 480;
	private int imageId = 0;
	private WeakReference<Bitmap> bitmap;
	private boolean isOnClick = false;

	private String selectResolution = null;
	private String wm = null;
	
	private OrientationEventListener mOrientationListener;
    private int mLastOrientation = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFormat(PixelFormat.TRANSLUCENT);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

		setContentView(R.layout.cameralayout);
		mSurfaceView = (SurfaceView) findViewById(R.id.camera);
		mSurfaceView.setOnClickListener(this);
		mSurfaceHolder = mSurfaceView.getHolder();
		mSurfaceHolder.addCallback(this);
		mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		
		mOrientationListener = new OrientationEventListener(this) {
			@Override
			public void onOrientationChanged(int orientation) {
				if (orientation != ORIENTATION_UNKNOWN) {
					orientation += 90;
				}
				orientation = roundOrientation(orientation);
				if (orientation != mLastOrientation) {
					mLastOrientation = orientation;
				}
			}
		};
		mOrientationListener.enable();
	}
	
	protected void setDisplayOrientation(Camera camera, int angle) {
		Method downPolymorphic;
		try {
			downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", new Class[] { int.class });
			if (downPolymorphic != null)
				downPolymorphic.invoke(camera, new Object[] { angle });
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public int roundOrientation(int orientationInput) {
		int orientation = orientationInput;

		if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
			orientation = 0;
		}

		orientation = orientation % 360;
		int retVal;
		if (orientation < (0 * 90) + 45) {
			retVal = 0;
		} else if (orientation < (1 * 90) + 45) {
			retVal = 90;
		} else if (orientation < (2 * 90) + 45) {
			retVal = 180;
		} else if (orientation < (3 * 90) + 45) {
			retVal = 270;
		} else {
			retVal = 0;
		}
		return retVal;
	}
	
	public static int getExifOrientation(String filepath) {
        int degree = 0;
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
        } catch (IOException ex) {
        	ex.printStackTrace();
        }
        if (exif != null) {
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
            if (orientation != -1) {
                switch(orientation) {
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        degree = 90;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        degree = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        degree = 270;
                        break;
                }
            }
        }
        return degree;
    }
	
	public boolean onKeyDown(int keyCode, KeyEvent paramKeyEvent) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			return onBackClick();
		} else if (keyCode == KeyEvent.KEYCODE_CAMERA) {
			try {
				mCamera.takePicture(mShutterCallback, null, mPictureCallback);
			} catch (Exception e) {
				e.printStackTrace();
				isOnClick = false;
			} catch (Error ex) {
				isOnClick = false;
			}
		}
		return super.onKeyDown(keyCode, paramKeyEvent);
	}

	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);
	}

	@Override
	protected void onRestart() {
		super.onRestart();
	}

	@Override
	protected void onResume() {
		super.onResume();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
	}

	@Override
	protected void onStart() {
		super.onStart();
	}

	@Override
	protected void onStop() {
		super.onStop();
	}

	@Override
	public void onClick(View v) {
		if (!isOnClick) {
			isOnClick = true;
			try {
				mCamera.autoFocus(new AutoFocusCallback() {
					@Override
					public void onAutoFocus(boolean success, Camera camera) {
						try {
							mCamera.takePicture(mShutterCallback, null, mPictureCallback);
						} catch (Exception e) {
							e.printStackTrace();
							isOnClick = false;
						} catch (Error ex) {
							isOnClick = false;
						}
					}

				});
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	PictureCallback mPictureCallback = new PictureCallback() {
		public void onPictureTaken(byte[] data, Camera camera1) {
			InputStream in = null;
			try {
				if (data != null) {
					File pictureFileDir = new File(Environment.getExternalStorageDirectory() + "/" + AppContext.SD_PATH, "temp");
		            if (!pictureFileDir.exists()) {
		                pictureFileDir.mkdirs();
		            }
		            File picFile = new File(pictureFileDir, "upload.jpeg");
		            if (!picFile.exists()) {
		            	picFile.createNewFile();
		            }
		            FileOutputStream fos = new FileOutputStream(picFile);
					fos.write(data);
					fos.close();
		            in = new FileInputStream(picFile);
					BitmapFactory.Options options1 = new BitmapFactory.Options();
					options1.inPurgeable = true;
					options1.inInputShareable = true;
					options1.inSampleSize = 2;
					try {
						BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(options1, true);
					} catch (Exception ex) {
						ex.printStackTrace();
					}
					bitmap = new WeakReference<Bitmap>(Bitmap.createScaledBitmap(BitmapFactory
							.decodeStream(in, null, options1), IMG_Width, IMG_Height, false));
					Bitmap bt = bitmap.get();
					int width = bt.getWidth();
					int height = bt.getHeight();
					Matrix matrix = new Matrix();
					matrix.setRotate(mLastOrientation);
					bitmap = new WeakReference<Bitmap>(Bitmap.createBitmap(bt, 0, 0, width, height, matrix, true));
					pictureFileDir = new File(Environment.getExternalStorageDirectory() + "/" + AppContext.SD_PATH, "upload");
					if (!pictureFileDir.exists()) {
		                pictureFileDir.mkdirs();
		            }
		            picFile = new File(pictureFileDir, "upload.jpeg");
		            if (!picFile.exists()) {
		            	picFile.createNewFile();
		            }
		            fos = new FileOutputStream(picFile);
					String pathName = picFile.getAbsolutePath();
					if (null != wm && !"".equals(wm.trim())) {
						bitmap = new WeakReference<Bitmap>(addWateMark(new WeakReference<Bitmap>(bitmap.get()).get(), wm));
						bitmap.get().compress(Bitmap.CompressFormat.JPEG, 100, fos);
					} else {
						bitmap.get().compress(Bitmap.CompressFormat.JPEG, 100, fos);
					}
					fos.close();
					bitmap.get().recycle();
					bitmap = null;
					System.gc();
					BitmapFactory.Options options = new BitmapFactory.Options();
					options.inJustDecodeBounds = true;
					// 计算缩放比
					int be = (int) (options.outHeight / (float) 200);
					if (be <= 0)
						be = 1;
					options.inSampleSize = be * 2;
					options1.inPurgeable = true;
					options1.inInputShareable = true;
					try {
						BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(options1, true);
					} catch (Exception ex) {
						ex.printStackTrace();
					}
					bitmap = new WeakReference<Bitmap>(BitmapFactory.decodeFile(pathName, options)); // 此时返回bm为空
					options.inJustDecodeBounds = false;
					bitmap = new WeakReference<Bitmap>(BitmapFactory.decodeFile(pathName, options)); // 此时返回bm为空
					if (mPreviewRunning) {
						mCamera.stopPreview();
						mPreviewRunning = false;
					}
					isOnClick = false;
					setResult(1006);
					finish();
				}
			} catch (Exception e) {
				e.printStackTrace();
				onBackClick();
			} catch (Error e) {
				e.printStackTrace();
				onBackClick();
			}
		}
	};
	
	public Bitmap getRotatedImage(Bitmap original, int degrees) {
	    Matrix matrix = new Matrix();
	    matrix.postRotate(degrees);

	    Bitmap rotated = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
	    return rotated;
	}
	
	private Point screenResolution;
	private Point cameraResolution;
	private static final Pattern COMMA_PATTERN = Pattern.compile(",");

	void initFromCameraParameters(Camera camera) {
		Camera.Parameters parameters = camera.getParameters();
		WindowManager manager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
		Display display = manager.getDefaultDisplay();
		screenResolution = new Point(display.getWidth(), display.getHeight());
		cameraResolution = getCameraResolution(parameters, screenResolution);
	}

	private Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {
		String previewSizeValueString = parameters.get("preview-size-values");
		if (previewSizeValueString == null) {
			previewSizeValueString = parameters.get("preview-size-value");
		}
		Point cameraResolution = null;
		if (previewSizeValueString != null) {
			cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
		}
		if (cameraResolution == null) {
			cameraResolution = new Point((screenResolution.x >> 3) << 3, (screenResolution.y >> 3) << 3);
		}
		return cameraResolution;
	}

	private Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) {
		int bestX = 0;
		int bestY = 0;
		int diff = Integer.MAX_VALUE;
		for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
			previewSize = previewSize.trim();
			int dimPosition = previewSize.indexOf('x');
			if (dimPosition < 0) {
				continue;
			}
			int newX;
			int newY;
			try {
				newX = Integer.parseInt(previewSize.substring(0, dimPosition));
				newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
			} catch (NumberFormatException nfe) {
				continue;
			}

			int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
			if (newDiff == 0) {
				bestX = newX;
				bestY = newY;
				break;
			} else if (newDiff < diff) {
				bestX = newX;
				bestY = newY;
				diff = newDiff;
			}

		}

		if (bestX > 0 && bestY > 0) {
			return new Point(bestX, bestY);
		}
		return null;
	}

	ShutterCallback mShutterCallback = new ShutterCallback() {

		public void onShutter() {

		}

	};

	public Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
		final double ASPECT_TOLERANCE = 0.05;
		double targetRatio = (double) w / h;
		if (sizes == null)
			return null;
		Size optimalSize = null;
		double minDiff = Double.MAX_VALUE;
		int targetHeight = h;
		for (Size size : sizes) {
			double ratio = (double) size.width / size.height;
			if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
				continue;
			if (Math.abs(size.height - targetHeight) < minDiff) {
				optimalSize = size;
				minDiff = Math.abs(size.height - targetHeight);
			}
		} 
		if (optimalSize == null) {
			minDiff = Double.MAX_VALUE;
			for (Size size : sizes) {
				if (Math.abs(size.height - targetHeight) < minDiff) {
					optimalSize = size;
					minDiff = Math.abs(size.height - targetHeight);
				}
			}
		}
		return optimalSize;
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

	}
	

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (mCamera != null) {
			return;
		}
		if (!mPreviewRunning) {
			mCamera = Camera.open();
			try {
				if (selectResolution == null) {
					initFromCameraParameters(mCamera);
				}

				Parameters params = mCamera.getParameters();
				params.setFocusMode(Parameters.FOCUS_MODE_AUTO);
				params.setFlashMode(Parameters.FLASH_MODE_AUTO);
				List<Size> list = params.getSupportedPictureSizes();
				int w = 0;
				int h = 0;
				for (int i = 0; i < list.size(); i++) {
					Size size = list.get(i);
					if (size.width >= IMG_Width && size.height >= IMG_Height) {
						if (w == 0) {
							w = size.width;
							h = size.height;
						} else if (w > size.width && h > size.height) {
							w = size.width;
							h = size.height;
						}
					}
				}
				if (w == 0) {
					Size size = list.get(0);
					w = size.width;
					h = size.height;
				}
				params.setPictureSize(w, h);
				Pattern pa = Pattern.compile("x");
				if (selectResolution != null) {
					String[] s = pa.split(selectResolution);
					cameraResolution = new Point(Integer.parseInt(s[0]), Integer.parseInt(s[1]));
				}

				params.setPreviewSize(cameraResolution.x, cameraResolution.y);
				if (Integer.parseInt(Build.VERSION.SDK) >= 8) {
					setDisplayOrientation(mCamera, mLastOrientation);
				} else {
					if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
						params.set("orientation", "portrait");
						params.set("rotation", mLastOrientation);
					}
					if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
						params.set("orientation", "landscape");
						params.set("rotation", mLastOrientation);
					}
				}
				params.setRotation(mLastOrientation);
				mCamera.setParameters(params);
				mCamera.setPreviewDisplay(holder);
				mCamera.startPreview();
				mPreviewRunning = true;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	protected void onDestroy() {
		bitmapRecycle();
		super.onDestroy();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		try {
			if (mCamera != null) {
				mCamera.stopPreview();
				mPreviewRunning = false;
				mCamera.release();
				mCamera = null;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void bitmapRecycle() {
		try {
			if (bitmap != null && bitmap.get() != null && !bitmap.get().isRecycled()) {
				bitmap.get().recycle();
				System.gc();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (mCamera != null) {
				mCamera.stopPreview();
				mPreviewRunning = false;
				mCamera.release();
				mCamera = null;
			}
		}
	}

	protected boolean onBackClick() {
		try {
			Bundle bundle = new Bundle();
			bundle.putInt("imageId", imageId);
			Intent intent = getIntent();
			intent.putExtras(bundle);
			if (bitmap != null) {
				setResult(1111, intent);
			} else {
				setResult(0, intent);
			}
			finish();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 添加水印
	 * @param str
	 * @param photo
	 */
	private Bitmap addWateMark(Bitmap photo, String str) {
		if (null == photo || null == str || "".equals(str.trim()))
			return null;
		int width = photo.getWidth(), hight = photo.getHeight();
		Bitmap icon = Bitmap.createBitmap(width, hight, Bitmap.Config.ARGB_8888); // 建立一个空的BItMap
		Canvas canvas = new Canvas(icon);// 初始化画布绘制的图像到icon上
		Paint photoPaint = new Paint(); // 建立画笔
		photoPaint.setDither(true); // 获取跟清晰的图像采样
		photoPaint.setFilterBitmap(true);// 过滤一些

		Rect src = new Rect(0, 0, photo.getWidth(), photo.getHeight());// 创建一个指定的新矩形的坐标
		Rect dst = new Rect(0, 0, width, hight);// 创建一个指定的新矩形的坐标
		canvas.drawBitmap(photo, src, dst, photoPaint);// 将photo 缩放或则扩大到
														// dst使用的填充区photoPaint

		Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);// 设置画笔
		textPaint.setTextSize(30.0f);// 字体大小
		textPaint.setTypeface(Typeface.DEFAULT_BOLD);// 采用默认的宽度
		textPaint.setColor(Color.RED);// 采用的颜色
		canvas.drawText(str, 0, hight - 50, textPaint);
		canvas.save(Canvas.ALL_SAVE_FLAG);
		canvas.restore();
		return icon;
	}
}
